<template>
  <div class="map-container">
    <!-- 地图 -->
    <div id="map" />

    <!-- 底图切换 -->
    <!-- <map-switch @switch="switchMap" /> -->

    <!-- 图层管理 -->
    <!-- <layer-manage @check="modifyIsChecked" /> -->

    <!-- 机场弹窗 -->
    <air-info id="airOverlay" :info="airportInfo" @hide="hideAirportInfo" />

    <!-- 问题弹窗 -->
    <!-- <question-info id="questionOverlay" :info="questionInfo" @hide="hideQuestionInfo" @showbig="showBigImage" /> -->

    <!-- 构造物弹窗 -->
    <!-- <structure-info id="structureOverlay" :info="structureInfo" @hide="hideStructureInfo" @showbig="showBigImage" /> -->

    <!-- 事故详情弹窗 -->
    <!-- <accident-info id="accidentOverlay" :info="accidentInfo" :accident-video="getAccidentVideo" @hide="hideAccidentInfo" @remove="removeAccident" /> -->
    <!-- 展示大图 -->
    <div v-if="mockShow" class="mock" @click="mockShow = !mockShow">
      <img v-show="mockShow" :src="previewPictureSrc">
    </div>
  </div>
</template>
<script>
// vue3
import { ref, reactive, toRefs, onMounted, onBeforeUnmount, watch, computed } from 'vue'
// openlayers 类
import 'ol/ol.css'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import { Map, View, Feature, Overlay } from 'ol'
import { Style, Circle, Stroke, Icon, Fill } from 'ol/style'
import CircleStyle from 'ol/style/Circle'
import { Point } from 'ol/geom'
import * as control from 'ol/control'
import * as interaction from 'ol/interaction'
import { transform, fromLonLat, getTransform } from 'ol/proj'
import { getVectorContext } from 'ol/render'
import GeoJSON from 'ol/format/GeoJSON.js'
import Cluster from 'ol/source/Cluster.js'
import { LineString, Polygon } from 'ol/geom'
import { unByKey } from 'ol/Observable'
import { Draw } from 'ol/interaction'
import { boundingExtent, getCenter } from 'ol/extent'
// turf
import * as turf from '@turf/turf'
// common tool
import imagesMap from '@/components/BaseMap/tools/gisImage.js'
import { gcj02towgs84 } from '@/utils/coordinate-util.js'
import gcj02Mecator from '@/utils/map/gcj02Mecator.js'
import { router } from '@/router/index'
// api
// import { getStructureQuestion } from '@/api/road/construct-manage/index.js' // 获取构造物问题数据
// import { getStructureSection } from '@/api/road/construct-manage/index.js' // 获取构造物数据
import { getAirList, getAirTask, getTaskVideo } from '@/api/task/index.js'
// import { getFlightData, getTelemetryData } from '@/api/flight-data/index.js' // 获取机场轨迹路线数据,最新一条遥测数据
// 组件
// import VideoPlayer from '@/components/VideoPlayer/player.vue'
// import ToolBar from '@/components/Map/ToolBar.vue'
import { geomStyles } from '@/utils/map/geomStyle'
import AirInfo from './components/AirInfo.vue'
// import MapSwitch from './components/MapSwitch.vue'
// import LayerManage from './components/LayerManage.vue'
// import QuestionInfo from './components/QuestionInfo.vue'
// import StructureInfo from './components/StructureInfo.vue'
// import AccidentInfo from './components/AccidentInfo.vue'

export default {
  components: { AirInfo },
  // components: { VideoPlayer, ToolBar, AirInfo, MapSwitch, LayerManage, QuestionInfo, StructureInfo, AccidentInfo },
  props: {
    param: {
      type: Object,
      default: () => { }
    },
    accidentVideo: {
      type: String,
      default: ''
    },
    airportList: {
      type: Array,
      default: () => []
    }
  },
  emits: ['coords', 'polygon'],
  setup(props, { emit }) {
    const data = reactive({
      map: null,
      view: null,
      // 天地图电子图
      tdtLineMap: null,
      // 天地图影像图
      tdtImgMap: null,
      // 长江流域水系图
      yangtzeRiver: null,
      drop: false,
      // 图层
      problemLayer: null, // 问题图层
      structorLayers: [], // 构造物图层数组
      hasImg: false, // 构造物是否有图片,没有图片则显示暂无图片
      airportLayer: null, // 机场图层
      // 覆盖物详情
      structureInfo: null, // 构造物详情
      airportInfo: null, // 机场详情
      // 覆盖物
      structureOverlay: null, // 构造物覆盖物
      airportList: [], // 机场列表
      liveIndex: false,
      taskId: null, // 任务id
      animateList: null,
      animateListLength: 0,
      trackLayer: null,
      percent: null, // 飞行的百分比
      // 预计直播总数据
      lineTrajectoryList: [
        { lng: '118.765591', lat: '32.050993' },
        { lng: '118.665591', lat: '32.150993' },
        { lng: '118.565591', lat: '32.070993' },
        { lng: '118.465591', lat: '32.020993' },
        { lng: '118.365591', lat: '32.110993' },
        { lng: '118.265591', lat: '32.080993' },
        { lng: '118.165591', lat: '32.150993' },
        { lng: '118.765591', lat: '32.150993' },
        { lng: '118.66551', lat: '32.050993' },
        { lng: '118.365591', lat: '32.060993' },
        { lng: '118.265591', lat: '32.180993' },
        { lng: '118.165591', lat: '32.050993' }
      ],
      lineTrajectoreIndex: 0, // 索引
      intervalId: null, // 直播定时器
      liveAnimation: null, // 直播轨迹动画
      trackInfo: null,
      liveTrackLayer: null,
      vectorLayer: null, //
      layerBoxShow: false,
      flightTrackLayer: null, // 直播轨迹
      markLayer: null, // 直播无人机图标图层
      previewPictureSrc: null, // 所展示的大图路径
      picturePreviewShow: false, // 是否展示大图
      mockShow: false, // 大图下的遮罩
      // 机场弹框相关
      airOverlay: null,
      airInfo: null,
      // 问题弹窗相关
      questionOverlay: null,
      questionInfo: null,
      airportBufferLayer: null, // 机场缓冲区图层
      airportBuffer: null, // 机场缓冲区
      // 绘制几何相关
      mapMouseMove: null,
      helpTooltipElement: null,
      feature: null,
      draw: null,
      listener: null,
      measureTooltipElement: null,
      measureTooltip: null,
      drawLayers: [],
      drawElements: [],
      lngLats_cpRPA: [], // cpRPA坐标系
      routeParam: null,
      routeLayer: null,
      // 事故弹窗相关
      accidentOverlay: null,
      accidentInfo: null,
      // 航线相关
      droneRouteLayer: null,
      accidentLayer: null
    })

    const getAccidentVideo = computed(() => {
      return props.accidentVideo || null
    })

    // 初始化地图
    const initMap = () => {
      // 电子地图
      data.tdtLineMap = new TileLayer({
        visible: false,
        // className: 'baseLayerClass',
        source: new XYZ({
          projection: gcj02Mecator,
          url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
          // url: 'https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=f634525a82da65f715d168d7ba1899c0'
        })
      })
      // 影像图
      data.tdtImgMap = new TileLayer({
        visible: true,
        source: new XYZ({
          projection: gcj02Mecator,
          // url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=6&x={x}&y={y}&z={z}'
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=6'
          // url: 'https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=f634525a82da65f715d168d7ba1899c0'
        })
      })
      data.tdtAnnotion = new TileLayer({
        visible: true,
        source: new XYZ({
          projection: gcj02Mecator,
          // url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&scl=1&size=1&style=1&x={x}&y={y}&z={z}'
          // url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=f634525a82da65f715d168d7ba1899c0'
          url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=8'
        })
      })
      // 江苏省长江流域
      data.yangtzeRiver = new VectorLayer({
        style: new Style({
          fill: new Fill({
            color: 'rgba(84,152,288)'
          })
        }),
        source: new VectorSource({
          url: 'https://geoserver.t-aaron.com:4080/geoserver/changjiang/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=changjiang%3Achangjiang&maxFeatures=50&outputFormat=application%2Fjson',
          format: new GeoJSON()
        })
      })
      data.view = new View({
        zoom: 9.5,
        maxZoom: 18,
        center: fromLonLat([119.7286, 32.0445])
      })

      data.map = new Map({
        target: 'map',
        view: data.view,
        layers: [data.tdtLineMap, data.tdtImgMap],
        // layers: [data.tdtLineMap, data.tdtImgMap, data.tdtAnnotion],
        controls: control.defaults({
          attribution: false,
          rotate: false,
          zoom: false
        }),
        interactions: interaction.defaults({
          // 禁止地图双击放大事件
          doubleClickZoom: false
        })
      })

      // 鼠标移到要素上时改变鼠标样式,由箭头变成小手
      data.map.on('pointermove', function(evt) {
        data.map.getTargetElement().style.cursor = data.map.hasFeatureAtPixel(evt.pixel)
          ? 'pointer'
          : ''
      })

      // 添加问题覆盖物
      data.questionOverlay = new Overlay({
        id: 'question_overlay',
        element: document.getElementById('questionOverlay'),
        offset: [10, 10]
      })
      // 添加构造物覆盖物
      data.structureOverlay = new Overlay({
        id: 'structure_overlay',
        element: document.getElementById('structureOverlay'),
        offset: [10, 10]
      })
      // 添加机场覆盖物
      data.airOverlay = new Overlay({
        id: 'air_overlay',
        element: document.getElementById('airOverlay'),
        offset: [-500, -300]
      })
      // 添加事故弹窗
      data.accidentOverlay = new Overlay({
        id: 'accident_overlay',
        element: document.getElementById('accidentOverlay'),
        offset: [10, 10]
      })

      // 加载机场
      watch(() => props.airportList, () => {
        getAirport()
      }, { deep: true })

      // 加载问题数据
      // getProblemData()
      // 加载构造物数据
      // getStructureData()
      // 点击事件
      data.map.on('click', (evt) => {
        show2ShowInfo(evt)
      })
    }

    const formatLngLat = (coord) => {
      const lngLat = []
      if (coord?.length) {
        coord.map(item => {
          lngLat.push(fromLonLat([parseFloat(item?.lng || item?.lon), parseFloat(item.lat)]))
        })
      }
      return lngLat
    }

    const clearTrack = () => {
      data.trackInfo = null
      // 清除无人机点、轨迹线图层
      if (data.trackLayer !== null) {
        data.map.removeLayer(data.trackLayer)
        data.trackLayer = null
      }
      clearRouteLayer()
    }

    const drawTrack = (info) => {
      const coords = formatLngLat(info)
      if (data.trackInfo) {
        const len = coords.length
        // 实时更新无人机路径和无人机位置
        data.trackInfo.route.appendCoordinate(coords[len - 1])
        data.trackInfo.geoMarker.getGeometry().setCoordinates(data.trackInfo.route.getLastCoordinate())
        data.trackInfo.vectorLayer.getSource().changed()
      } else {
        data.trackInfo = initTrack(coords)
      }
    }

    const initTrack = (coordinate) => {
      let vectorLayer = null
      const route = new LineString(coordinate)
      // 新建轨迹数据源
      const routeFeature = new Feature({
        type: 'route',
        geometry: route
      })
      // 新建点数据源
      const geoMarker = new Feature({
        type: 'geoMarker',
        geometry: new Point(route.getLastCoordinate())
      })
      // 统计创建矢量图层
      vectorLayer = new VectorLayer({
        source: new VectorSource({
          features: [geoMarker, routeFeature]
        }),
        style: function(feature) {
          return geomStyles(feature.get('type'))
        },
        zIndex: getMaxZLayer() + 1
      })

      data.trackLayer = vectorLayer
      data.map.addLayer(data.trackLayer)
      data.view.fit(route, { padding: [50, 50, 50, 50] })
      return {
        vectorLayer,
        geoMarker,
        route
      }
    }

    const clearRouteLayer = () => {
      // 清除航线图层
      if (data.droneRouteLayer !== null) {
        data.map.removeLayer(data.droneRouteLayer)
        data.droneRouteLayer = null
      }
    }

    /**
     *  绘制航线
     * @param {*} info
     */
    const drawDroneRoute = (info, airPortId) => {
      clearRouteLayer()
      const lngLats = info || []
      if (lngLats.length === 0) return
      lngLats.push(lngLats[0])
      const routeStops = formatLngLat(lngLats)
      const route = new LineString(routeStops)
      // 新建航线数据源
      const routeFeature = new Feature({
        type: 'droneRoute',
        geometry: route
      })
      // 新建航线中断点数据源
      const stopFeatures = []
      routeStops.map((lngLat) => {
        const stopFeature = new Feature({
          type: 'routeStop',
          geometry: new Point(lngLat)
        })
        stopFeatures.push(stopFeature)
      })
      // 统计创建矢量图层
      data.droneRouteLayer = new VectorLayer({
        source: new VectorSource({
          features: [...stopFeatures, routeFeature]
        }),
        style: function(feature) {
          return geomStyles(feature.get('type'))
        },
        zIndex: getMaxZLayer() + 1
      })

      data.map.addLayer(data.droneRouteLayer)
      data.view.fit(route, { padding: [50, 50, 50, 50] })
    }

    const removeAccident = () => {
      if (data.accidentLayer !== null) {
        data.map.removeLayer(data.accidentLayer)
        data.accidentLayer = null
        hideAccidentInfo()
      }
    }

    const addAccident = (info) => {
      let layer
      // 点
      if (info?.lineType === 1) {
        const point = new Point(formatLngLat(info?.accidentRegionList)[0])
        // point.applyTransform(getTransform('EPSG:4326', 'EPSG:3857'))
        const feature = new Feature(point)
        // 设置属性
        feature.setProperties({
          // 类型
          type: 'accident',
          // 属性
          props: info
        }, false)
        const source = new VectorSource({
          features: [feature]
        })
        const layer = new VectorLayer({
          source: source,
          style: geomStyles('accident'),
          zIndex: getMaxZLayer() + 1
        })
        data.accidentLayer = layer
        data.map.addLayer(data.accidentLayer)
        addAccidentOverlay(feature)
        fitLayer(layer)

        // 点闪烁效果
        let radius = 0
        layer.on('postrender', (e) => {
          // 最大点半径 常量 可修改
          const maxcRadius = 40
          if (radius > maxcRadius) {
            radius = 0
          }
          // 不透明度
          const opacity = (maxcRadius - radius) * (1 / maxcRadius)
          // 点的样式
          const pointStyle = new Style({
            image: new Circle({
              // 半径
              radius: radius,
              // 线条样式
              stroke: new Stroke({
                // 颜色
                color: 'rgba(255, 0, 0, ' + opacity + ')',
                // 宽度
                width: 5 - radius / 10
              })
            })
          })

          // 获取矢量要素上下文
          const vectorContext = getVectorContext(e)
          vectorContext.setStyle(pointStyle)
          vectorContext.drawGeometry(feature.getGeometry())
          // 闪烁速度
          radius = radius + 0.6
          // 请求地图渲染(在下一动画帧处)
          data.map.render()
        })

        return layer
      } else if (info?.lineType === 2) { // 线
        const line = new LineString(formatLngLat(info?.accidentRegionList))
        // line.applyTransform(getTransform('EPSG:4326', 'EPSG:3857'))
        const feature = new Feature(line)
        // 设置样式
        feature.setStyle(
          new Style({
            stroke: new Stroke({
              color: 'red',
              width: 5
            })
          })
        )
        // 设置属性
        feature.setProperties({
          // 类型
          type: 'accident',
          // 属性
          props: info
        }, false)
        const source = new VectorSource({
          features: [feature]
        })
        const layer = new VectorLayer({
          source: source,
          zIndex: getMaxZLayer() + 1
        })
        data.accidentLayer = layer
        data.map.addLayer(data.accidentLayer)
        addAccidentOverlay(feature)
        fitLayer(layer)

        return layer
      } else { // 面
        const polygon = new Polygon([formatLngLat(info?.accidentRegionList)])
        // polygon.applyTransform(getTransform('EPSG:4326', 'EPSG:3857'))
        const feature = new Feature(polygon)
        // 设置样式
        feature.setStyle(
          new Style({
            stroke: new Stroke({
              color: 'red',
              width: 5
            }),
            fill: new Fill({
              color: 'rgba(255, 0, 0, 0.6)'
            })
          })
        )
        // 设置属性
        feature.setProperties({
          // 类型
          type: 'accident',
          // 属性
          props: info
        }, false)
        const source = new VectorSource({
          features: [feature]
        })
        const layer = new VectorLayer({
          source: source,
          zIndex: getMaxZLayer() + 1
        })
        data.accidentLayer = layer
        data.map.addLayer(data.accidentLayer)
        addAccidentOverlay(feature)
        fitLayer(layer)

        return layer
      }
    }

    const addAccidentOverlay = (feature) => {
      const properties = feature.getProperties()
      const geometry = properties.geometry
      let coord = []
      if (geometry instanceof Point) {
        coord.push(geometry.flatCoordinates[0], geometry.flatCoordinates[1])
      } else if (geometry instanceof LineString) {
        coord = geometry.getFirstCoordinate()
      } else if (geometry instanceof Polygon) {
        const pointCoord = geometry.getInteriorPoint().flatCoordinates
        coord.push(pointCoord[0], pointCoord[1])
      }
      // 弹窗位置
      data.map.addOverlay(data.accidentOverlay)
      data.accidentOverlay.setPosition(coord)
      // 赋予属性值
      data.accidentInfo = properties.props
      // 新点击的弹框在最上面
      data.accidentOverlay.getElement().parentElement.style.zIndex = getMaxZOverlay() + 1
    }

    const removeLayer = (layer) => {
      data.map.removeLayer(layer)
    }

    /**
     *  添加点图层
     */
    const addPointLayer = (dataList, option) => {
      if (dataList?.length > 0) {
        // feature集合
        const Features = []
        dataList.map((item) => {
          // 用于存放经纬度
          const lngLat = []
          // 如果是高德坐标系，则需要转化
          if (option?.amap_coord) {
            const coord = gcj02towgs84(parseFloat(item?.longitude || item?.lng), parseFloat(item?.latitude || item?.lat))
            lngLat.push(coord.longitude, coord.latitude)
          } else {
            lngLat.push(parseFloat(item?.longitude || item?.lng), parseFloat(item?.latitude || item?.lat))
          }
          // lngLat.push(parseFloat(item?.longitude || item?.lng), parseFloat(item?.latitude || item?.lat))
          // 创建feature
          const feature = new Feature({
            geometry: new Point(fromLonLat(lngLat))
          })
          // 设置属性
          feature.setProperties({
            // 类型
            type: option?.type,
            // 属性
            props: item
          }, false)
          Features.push(feature)
        })
        const pointLayer = new VectorLayer({
          source: new VectorSource({
            features: Features
          }),
          style: (feature) => {
            // 根据type设置不同的点图层样式
            return geomStyles(
              option?.type,
              feature.getProperties().props
            )
          },
          zIndex: option?.zIndex || 9
        })
        data.map.addLayer(pointLayer)
        return {
          pointLayer,
          Features
        }
      }
    }

    /**
     * 底图切换
     * @param {*} val
     */
    const switchMap = (val) => {
      switch (val) {
        case '电子图':
          data.tdtImgMap.setVisible(false)
          data.tdtLineMap.setVisible(true)
          break
        case '影像图':
          data.tdtImgMap.setVisible(true)
          data.tdtLineMap.setVisible(false)
      }
    }

    // // 加载问题数据
    // const getProblemData = async() => {
    //   data.problemLayer = null
    //   const res = await getStructureQuestion()
    //   if (res.code === 0) {
    //     if (res?.data?.length) {
    //       data.problemLayer = addPointLayer(
    //         res?.data,
    //         {
    //           type: 'question',
    //           zIndex: 13
    //         }
    //       ).pointLayer
    //     }
    //   }
    // }
    // // 加载构造物数据
    // const getStructureData = async() => {
    //   data.structorLayers = []
    //   const res = await getStructureSection()
    //   if (res.code === 0) {
    //     if (res?.data?.length) {
    //       res?.data.map((item) => {
    //         if (item?.structureType !== 8) {
    //           const layer = addPointLayer(
    //             [item],
    //             {
    //               type: 'structure',
    //               amap_coord: true,
    //               zIndex: 12
    //             }
    //           ).pointLayer
    //           data.structorLayers.push(layer)
    //         }
    //       })
    //     }
    //   }
    // }

    // 点击矢量图层事件
    const show2ShowInfo = (evt) => {
      // 防止冒泡
      evt.stopPropagation()
      // 点击位置的经纬度
      let feature = null
      feature = data.map.forEachFeatureAtPixel(evt.pixel, (feature) => {
        return feature
      })
      if (feature) {
        const properties = feature.getProperties()
        const type = properties.type
        if (type === 'question') {
          // 赋值
          data.questionInfo = properties.props
          // 弹窗位置
          data.map.addOverlay(data.questionOverlay)
          data.questionOverlay.setPosition(properties.geometry.flatCoordinates)
          // 新点击的弹框在最上面
          data.questionOverlay.getElement().parentElement.style.zIndex = getMaxZOverlay() + 1
          return false
        }
        if (type === 'structure') {
          // 赋值
          data.structureInfo = properties.props
          // 弹窗位置
          data.map.addOverlay(data.structureOverlay)
          data.structureOverlay.setPosition(properties.geometry.flatCoordinates)
          // 新点击的弹框在最上面
          data.structureOverlay.getElement().parentElement.style.zIndex = getMaxZOverlay() + 1
          return false
        }
        if (type === 'airport') {
          if (data.airOverlayId === properties.props.id) { // 再次点击关闭弹窗
            hideAirportInfo()
            return
          }
          // 赋予属性值
          data.airportInfo = properties.props
          console.log(properties.props)
          data.airOverlayId = properties.props.id
          data.map.addOverlay(data.airOverlay)
          // 弹窗位置 1.1.0版本修改为一直在当前地图中央展示
          // data.airOverlay.setPosition(properties.geometry.flatCoordinates)
          const currentExtent = data.view.calculateExtent(data.map.getSize())
          const currentCenter = getCenter(currentExtent)
          data.airOverlay.setPosition(currentCenter)
          // 新点击的弹框在最上面
          data.airOverlay.getElement().parentElement.style.zIndex = getMaxZOverlay() + 1
          return false
        }
        if (type === 'accident') {
          addAccidentOverlay(feature)
          return false
        }
      }
    }

    // 关闭机场显示信息
    const hideAirportInfo = () => {
      if (data.map.getOverlayById('air_overlay')) {
        data.airportInfo = null
        data.map.removeOverlay(data.airOverlay)
        data.airOverlayId = null
      }
    }
    // 关闭问题显示弹窗
    const hideQuestionInfo = () => {
      if (data.map.getOverlayById('question_overlay')) {
        data.map.removeOverlay(data.questionOverlay)
        data.questionInfo = null
      }
    }
    // 关闭覆盖物显示信息
    const hideStructureInfo = () => {
      if (data.map.getOverlayById('structure_overlay')) {
        data.map.removeOverlay(data.structureOverlay)
        data.structureInfo = null
      }
    }
    // 关闭应急事故弹窗
    const hideAccidentInfo = () => {
      if (data.map.getOverlayById('accident_overlay')) {
        data.map.removeOverlay(data.accidentOverlay)
        // data.accidentOverlay.setPosition(undefined)
        data.accidentInfo = null
      }
    }
    // 大图显示
    const showBigImage = (url) => {
      data.previewPictureSrc = url
      data.mockShow = true
    }

    // 获取机场
    const getAirport = () => {
      if (props.airportList.length > 0) {
        const { pointLayer } = addPointLayer(
          props.airportList,
          {
            type: 'airport'
          })
        fitLayer(pointLayer)
      }
    }

    // const getAirport = async function() {
    //   const res = await getAirList()
    //   if (res.code === 0) {
    //     data.airportList = res?.data?.records
    //     if (data.airportList?.length) {
    //       // 添加机场点图层
    //       addPointLayer(
    //         data.airportList,
    //         {
    //           type: 'airport',
    //           amap_coord: true
    //         })
    //     }
    //   }
    //   // addPointLayer(
    //   //   airport,
    //   //   {
    //   //     type: 'airport',
    //   //     amap_coord: true
    //   //   })
    // }
    // 图层显隐
    const modifyIsChecked = (item) => {
      switch (item.name) {
        case '构造物':
          data.structorLayers.map((layer) => {
            if (layer) {
              layer.setVisible(item.isChecked)
            }
          })
          if (!item.isChecked) {
            hideStructureInfo()
          }
          break
        case '问题':
          data.problemLayer.setVisible(item.isChecked)
          if (!item.isChecked) {
            hideQuestionInfo()
          }
          break
        default:
          break
      }
    }

    /**
     *  清除测量
     */
    const clearDrawGeometry = () => {
      data.drawLayers.map((layer) => {
        if (layer) {
          data.map.removeLayer(layer)
        }
      })
      data.drawElements.map((overlay) => {
        if (overlay) {
          data.map.removeOverlay(overlay)
        }
      })

      data.drawLayers = []
      data.drawElements = []

      data.map.removeInteraction(data.draw)
      unByKey(data.listener)
      unByKey(data.mapMouseMove)

      emit('coords', [])
      emit('polygon', [])
      clearRoute()
    }

    // 监听角度、间隔
    watch(() => props.param, (value) => {
      if (value) {
        data.routeParam = value
        if (data.lngLats_cpRPA.length > 0) {
          createRoute()
        }
      }
    })

    /**
     * 绘制几何
     * @param { 几何类型} geomType
     */
    const drawGeometry = (geomType) => {
      // 清除上一个绘制
      clearDrawGeometry()
      // 清除航线
      clearRoute()
      data.lngLats_cpRPA = []
      // 创建一个数据源,用于放置绘制过程中和绘制结束后的线段
      const source = new VectorSource()
      // 添加图层，用来放置数据源
      const layer = new VectorLayer({
        source: source,
        style: [
          new Style({
            fill: new Fill({
              color: 'rgba(16, 227, 157, 0.2)'
            }),
            stroke: new Stroke({
              color: 'rgba(16, 227, 157, 1)',
              width: 4
            }),
            image: new CircleStyle({
              radius: 8,
              stroke: new Stroke({
                color: 'rgba(16, 227, 157, 1)'
              })
            })
          }),
          new Style({
            image: new CircleStyle({
              radius: 4,
              fill: new Fill({
                color: 'rgba(16, 227, 157, 1)'
              })
            })
          })
        ]
      })
      data.mapMouseMove = data.map.on('pointermove', (evt) => {
        if (evt.dragging) {
          return
        }
        let helpMsg = '单击选择起点'
        if (data.feature) {
          helpMsg = '双击结束选点'
        }
        data.helpTooltipElement.innerHTML = helpMsg
        data.helpTooltip.setPosition(evt.coordinate)
        data.helpTooltipElement.classList.remove('hidden')
      })

      data.map.getViewport().addEventListener('mouseout', () => {
        data.helpTooltipElement.classList.add('hidden')
      })

      data.draw = new Draw({
        source,
        // 测量方式 Polygon 或者 LineString
        type: geomType,
        style: [
          new Style({
            fill: new Fill({
              color: 'rgba(216, 216, 216, 0.2)'
            }),
            stroke: new Stroke({
              color: 'rgba(216, 216, 216, 1)',
              lineDash: [10, 10],
              width: 4
            }),
            image: new CircleStyle({
              radius: 8,
              stroke: new Stroke({
                color: 'rgba(16, 227, 157, 1)'
              })
            })
          }),
          new Style({
            image: new CircleStyle({
              radius: 4,
              fill: new Fill({
                color: 'rgba(16, 227, 157, 1)'
              })
            })
          })
        ]
      })

      // 开始进行绘制
      data.draw.on('drawstart', (evt) => {
        data.feature = evt.feature
        let tooltipCoord = evt.coordinate
        data.listener = data.feature.getGeometry().on('change', (evt) => {
          const geom = evt.target
          if (geom instanceof Polygon) {
            tooltipCoord = geom.getInteriorPoint().getCoordinates()
          } else if (geom instanceof LineString) {
            tooltipCoord = geom.getLastCoordinate()
          }
          data.measureTooltip.setPosition(tooltipCoord)
        })
      })

      // 绘制完成
      data.draw.on('drawend', (evt) => {
        // data.measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'
        data.measureTooltip.setOffset([0, -7])
        data.feature = null
        data.measureTooltipElement = null
        // createMeasureTooltip()
        data.map.removeInteraction(data.draw)
        unByKey(data.listener)
        unByKey(data.mapMouseMove)

        var feature = evt.feature
        var geometry = feature.getGeometry()
        var coordinate = geometry.getCoordinates()
        const lngLats = []
        if (geometry instanceof Point) {
          const coord = transform(
            coordinate,
            'EPSG:3857',
            'EPSG:4326'
          )
          lngLats.push(coord)
          if (boolContainPoints(data.airportBuffer, lngLats)) {
            emit('coords', lngLats)
          } else {
            $message.error('超过机场覆盖范围!')
            clearDrawGeometry()
            // 重新画点
            drawGeometry('Point')
            return false
          }
        } else if (geometry instanceof LineString) {
          /**
           *  turf插件判断面是否包含线有bug具体原因不明，后续再看
           *  换个思路，多边形所有点都在面内，即为包含
           */
          coordinate.map((item) => {
            lngLats.push(
              transform(
                item,
                'EPSG:3857',
                'EPSG:4326'
              ))
          })
          // const line = turf.lineString(lngLats)
          if (boolContainPoints(data.airportBuffer, lngLats, 'lineString')) {
            data.routeLayer = drawRoute(coordinate).routeLayer
            emit('coords', lngLats)
          } else {
            $message.error('超过机场覆盖范围!')
            clearDrawGeometry()
            // 重新画线
            drawGeometry('LineString')
            return false
          }
        } else if (geometry instanceof Polygon) {
          data.lngLats_cpRPA = []
          coordinate[0].map((item) => {
            const coord = transform(
              item,
              'EPSG:3857',
              'EPSG:4326'
            )
            lngLats.push(coord)
            data.lngLats_cpRPA.push(
              {
                lat: coord[1],
                lng: coord[0]
              }
            )
          })

          if (boolContainPoints(data.airportBuffer, lngLats, 'polygon')) {
            emit('polygon', lngLats)
            createRoute()
          } else {
            $message.error('超过机场覆盖范围!')
            clearDrawGeometry()
            // 重新画面
            drawGeometry('Polygon')
            return false
          }
        }
      })

      createHelpTooltip()
      createMeasureTooltip()
      data.map.addLayer(layer)
      data.drawLayers.push(layer)
      data.map.addInteraction(data.draw)
    }

    const createMeasureTooltip = () => {
      if (data.measureTooltipElement) {
        data.measureTooltipElement.parentNode.removeChild(data.measureTooltipElement)
      }
      data.measureTooltipElement = document.createElement('div')
      // data.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure'
      data.measureTooltip = new Overlay({
        element: data.measureTooltipElement,
        offset: [0, -15],
        positioning: 'bottom-center',
        stopEvent: false,
        insertFirst: false
      })
      data.drawElements.push(data.measureTooltip)
      data.map.addOverlay(data.measureTooltip)
    }

    const createHelpTooltip = () => {
      if (data.helpTooltipElement) {
        data.helpTooltipElement.parentNode.removeChild(data.helpTooltipElement)
      }
      data.helpTooltipElement = document.createElement('div')
      data.helpTooltipElement.className = 'ol-tooltip hidden'
      data.helpTooltip = new Overlay({
        element: data.helpTooltipElement,
        offset: [15, 0],
        positioning: 'center-left'
      })
      data.map.addOverlay(data.helpTooltip)
    }

    /**
     * cpRPA生成航线
     * @param {角度 0-360} angle
     * @param {间隔 米} interval
     */
    const createRoute = () => {
      clearRoute()
      const lngLats = []
      let coordinate = []
      if (data.lngLats_cpRPA.length) {
        var polyline = cpRPA.setOptions({
          polygon: data.lngLats_cpRPA,
          rotate: data.routeParam?.angle || 0,
          space: data.routeParam?.interval || 5
        })
        coordinate = formatPolyline(polyline)
        if (coordinate?.length) {
          data.routeLayer = drawRoute(coordinate).routeLayer
          coordinate.map((item) => {
            lngLats.push(
              transform(
                item,
                'EPSG:3857',
                'EPSG:4326'
              ))
          })
        }
        emit('coords', lngLats)
      }
    }

    const clearRoute = () => {
      if (data.routeLayer) {
        data.map.removeLayer(data.routeLayer)
        data.routeLayer = null
      }
    }

    /**
     * 绘制机场覆盖缓冲区
     * @param {*} id
     */
    const drawAirportBuffer = (lngLat, coverage) => {
      // 清除已有机场缓冲区
      clearAirportBuffer()
      // 绘制缓冲区
      // 机场覆盖范围为非必填字段,未填覆盖范围按20公里算
      const drawBuffer = drawPointBuffer(lngLat, parseFloat(coverage) || 2)
      data.airportBufferLayer = drawBuffer.layer
      data.airportBuffer = drawBuffer.buffered
    }

    const clearAirportBuffer = () => {
      if (data.airportBufferLayer) {
        data.map.removeLayer(data.airportBufferLayer)
        data.airportBufferLayer = null
      }
      data.airportBuffer = null
    }

    /**
     * 绘制点的缓冲区
     * @param {*} lngLat
     * @param {*} range
     */
    const drawPointBuffer = (lngLat, range) => {
      var point = turf.point(lngLat)
      var buffered = turf.buffer(
        point,
        range,
        { units: 'kilometers', steps: 64 }
      )
      const polygon = new Polygon([buffered.geometry.coordinates[0]])
      polygon.applyTransform(getTransform('EPSG:4326', 'EPSG:3857'))
      const source = new VectorSource({
        features: [new Feature(polygon)]
      })
      const layer = new VectorLayer({
        source: source,
        // 设置样式，边框和填充
        style: new Style({
          // stroke: new Stroke({
          //   color: 'red',
          //   width: 5
          // }),
          fill: new Fill({
            color: 'rgba(39, 85, 145, 0.4)'
          })
        })
      })

      data.map.addLayer(layer)
      fitLayer(layer)
      return {
        layer,
        buffered
      }
    }

    /**
     * 判断空间几何包含
     * 如果第二个几何图形完全包含在第一个几何图形中，返回 true
     * @param {*} baseFeature
     * @param {*} proFeature
     */
    const boolContainPoints = (baseFeature, coords) => {
      let boolContain = true
      coords.map((item) => {
        if (
          !turf.booleanContains(baseFeature,
            turf.point(item)
          )
        ) {
          boolContain = false
        }
      })

      return boolContain
    }

    // 画航线
    const drawRoute = (lngLats) => {
      const route = new LineString(lngLats)
      const routeFeature = new Feature({
        type: 'route',
        geometry: route
      })
      const startPoint = new Feature({
        type: 'start',
        geometry: new Point(lngLats[0])
      })
      const endPoint = new Feature({
        type: 'end',
        geometry: new Point(lngLats[lngLats.length - 1])
      })
      const routeLayer = new VectorLayer({
        source: new VectorSource({
          features: [startPoint, endPoint, routeFeature]
        }),
        style: function(feature) {
          return geomStyles(feature.get('type'))
        }
      })
      routeLayer.setZIndex(getMaxZLayer() + 1)
      data.map.addLayer(routeLayer)

      return {
        routeLayer
      }
    }

    const formatPolyline = (coordinate) => {
      const lngLats = []
      coordinate.map((item) => {
        lngLats.push(fromLonLat([parseFloat(item.lng), parseFloat(item.lat)]))
      })
      return lngLats
    }

    const fitLayer = (layer) => {
      // 获取图层范围并定位
      if (layer) {
        const layerExtent = layer.getSource().getExtent()
        data.view.fit(layerExtent, {
          padding: [200, 100, 100, 0]
        })
      }
    }

    // 获取多个图层的范围
    const getLayerExtent = (layers) => {
      if (!layers || layers.length === 0) {
        return console.log('图层数组为空，请确认参数')
      }
      const coordinates = []
      layers.forEach(layer => {
        const extend = layer.getSource().getExtent()
        if (!extend) {
          return
        }
        // 获取左下角坐标点
        const minxy = [extend[0], extend[1]]
        // 获取右上角坐标点
        const maxxy = [extend[2], extend[3]]
        coordinates.push(minxy)
        coordinates.push(maxxy)
      })
      if (coordinates.length === 0) return null
      // 获取所有坐标点的最小矩形
      const result = boundingExtent(coordinates)
      return result
    }

    const fitExtent = (extent) => {
      data.view.fit(extent, {
        padding: [100, 100, 100, 100]
      })
    }

    /**
     *  获取打开overlay中最大的 z-index
     */
    const getMaxZOverlay = () => {
      let maxZIndex = 0
      const overlays = data.map.getOverlays().array_
      if (overlays.length) {
        overlays.forEach((item) => {
          const zIndex = item.getElement().parentElement.style.zIndex
          if (zIndex > maxZIndex) {
            maxZIndex = zIndex
          }
        })
      }
      return maxZIndex
    }

    /**
     *  获取所有图层中最大的z-index
     */
    const getMaxZLayer = () => {
      let maxZIndex = 0
      const layers = data.map.getAllLayers()
      if (layers.length) {
        layers.map((lay) => {
          const zIndex = lay.getZIndex()
          if (zIndex > maxZIndex) {
            maxZIndex = zIndex
          }
        })
      }
      return maxZIndex
    }

    // cpRPA 的一些参数
    const distance = (p1, p2) => {
      const point1 = turf.point([parseFloat(p1.lng), parseFloat(p1.lat)])
      const point2 = turf.point([parseFloat(p2.lng), parseFloat(p2.lat)])
      return turf.distance(point1, point2, { units: 'meters' })
    }

    const latlng2Px = (latlng) => {
      const pixel = data.map.getPixelFromCoordinate(fromLonLat([latlng.lng, latlng.lat]))
      return {
        x: pixel[0],
        y: pixel[1]
      }
    }

    const px2Latlng = (px) => {
      const coord = transform(
        data.map.getCoordinateFromPixel(px),
        'EPSG:3857',
        'EPSG:4326'
      )
      return {
        lat: coord[1],
        lng: coord[0]
      }
    }

    onMounted(() => {
      initMap()
      // 初始化cpRPA
      cpRPA.setDistanceFn(distance)
      cpRPA.setLatlng2PxFn(latlng2Px)
      cpRPA.setPx2LatlngFn(px2Latlng)
    })

    return {
      ...toRefs(data),
      hideStructureInfo,
      hideQuestionInfo,
      hideAirportInfo,
      hideAccidentInfo,
      modifyIsChecked,
      showBigImage,
      switchMap,
      drawAirportBuffer,
      clearAirportBuffer,
      drawGeometry,
      clearDrawGeometry,
      clearRoute,
      addAccident,
      removeLayer,
      drawDroneRoute,
      formatLngLat,
      drawTrack,
      initTrack,
      clearTrack,
      removeAccident,
      addPointLayer,
      getAccidentVideo,
      fitLayer,
      getLayerExtent,
      fitExtent
    }
  }
}
</script>
<style>
.baseLayerClass {
  filter: grayscale(100%) sepia(50%) invert(100%) saturate(250%);
  /* filter:grayscale(100%) */
}
</style>
<style lang='scss' scoped>
.map-container {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;

  :deep(.ol-viewport) {
    position: absolute !important;
  }
}

#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}

.mock {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.3);
  display: flex;
  justify-content: center;
  align-items: center;
}

::v-deep(.hidden) {
  display: none;
}

::v-deep(.ol-tooltip) {
  position: relative;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 4px;
  color: white;
  padding: 4px 8px;
  opacity: 0.7;
  white-space: nowrap;
  font-size: 12px;
  cursor: default;
  user-select: none;
}

::v-deep(.ol-tooltip-measure) {
  opacity: 1;
  font-weight: bold;
}

::v-deep(.ol-tooltip-static) {
  background-color: #ffcc33;
  color: black;
  border: 1px solid white;
}

::v-deep(.ol-tooltip-measure:before),
::v-deep(.ol-tooltip-static:before) {
  border-top: 6px solid rgba(0, 0, 0, 0.5);
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}

::v-deep(.ol-tooltip-static:before) {
  border-top-color: #ffcc33;
}
</style>
